﻿using MikuMikuLibrary.Archives;
using MikuMikuLibrary.Archives.Farc;
using MikuMikuLibrary.IO;
using MikuMikuLibrary.Models;
using MikuMikuLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MikuMikuLibrary.Databases;
using System.IO;
using MikuMikuLibrary.Models.Processing;

namespace ft_module_parser.pdaconversion.divaf2nd
{
    class objset
    {
        ushort FindUnusedID(StageDatabase staged)
        {
            ushort id = 0;

            var stage = staged.Stages.Where(c => c.Id == 0).FirstOrDefault();
            while (stage != null)
            {
                id++;
                stage = staged.Stages.Where(c => c.Id == id).FirstOrDefault();

            }
            Console.WriteLine("new stage at id = " + id);
            return id;
        }

        ushort FindUnusedID(ObjectDatabase staged)
        {
            ushort id = 0;

            var stage = staged.Objects.Where(c => c.Id == 0).FirstOrDefault();
            while (stage != null)
            {
                id++;
                stage = staged.Objects.Where(c => c.Id == id).FirstOrDefault();

            }
            Console.WriteLine("new object at id = " + id);
            return id;
        }

        public void GenerateObjSet(string filePath, ObjectDatabase objdb, StageDatabase staged, string acpath, bool doProcess = true, bool debug = false)
        {

            var stgpv = new Model();
            var textures = new MikuMikuLibrary.Textures.TextureSet();
            var texdb = new TextureDatabase();

            using (var farcArchive = BinaryFile.Load<FarcArchive>(filePath))
            using (var entryStream = farcArchive.Open(farcArchive.Entries.Where(c => c.Contains("txi")).First(), EntryStreamMode.MemoryStream))
                texdb.Load(entryStream);

            if (debug)
            {
                string farcpath = acpath + "\\rom\\objset\\" + Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8") + ".farc";

                using (var farcArchive = BinaryFile.Load<FarcArchive>(farcpath))
                using (var entryStream = farcArchive.Open(farcArchive.Entries.Where(c => c.Contains("tex")).First(), EntryStreamMode.MemoryStream))
                    textures.Load(entryStream);

                using (var farcArchive = BinaryFile.Load<FarcArchive>(farcpath))
                using (var entryStream = farcArchive.Open(farcArchive.Entries.Where(c => c.Contains("obj")).First(), EntryStreamMode.MemoryStream))
                    stgpv.Load(entryStream, textures, texdb);

            }
            else
            {
                using (var farcArchive = BinaryFile.Load<FarcArchive>(filePath))
                using (var entryStream = farcArchive.Open(farcArchive.Entries.Where(c => c.Contains("txd")).First(), EntryStreamMode.MemoryStream))
                    textures.Load(entryStream);

                using (var farcArchive = BinaryFile.Load<FarcArchive>(filePath))
                using (var entryStream = farcArchive.Open(farcArchive.Entries.First(), EntryStreamMode.MemoryStream))
                    stgpv.Load(entryStream, textures, texdb);

            }


            var objentry = new ObjectEntry();
            objentry.ArchiveFileName = Path.GetFileName(filePath).Replace("stgpv0", "stgpv8");
            objentry.FileName = Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8") + "_obj.bin";
            objentry.Id = FindUnusedID(objdb);
            objentry.Name = Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8");
            objentry.TextureFileName = Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8") + "_tex.bin";



            int ground_id = -1;

            ushort counter = 1;
            foreach (var meshes in stgpv.Meshes)
            {
                meshes.SubMeshes.RemoveAll(x => x.Vertices == null || x.Vertices.Length == 0);

                var meshentry = new MeshEntry();
                meshes.Id = counter;
                meshentry.Id = (ushort)meshes.Id;
                meshentry.Name = meshes.Name;

                if (meshes.Name.Contains("GND"))
                    ground_id = meshes.Id;

                objentry.Meshes.Add(meshentry);

                if (doProcess)
                {

                    if (!debug)
                    {
                        foreach (var submeshes in meshes.SubMeshes)
                        {
                            foreach (var indexTable in submeshes.IndexTables)
                            {
                                ushort[] triangleStrip = Stripifier.Stripify(indexTable.Indices);
                                if (triangleStrip != null)
                                {
                                    indexTable.PrimitiveType = PrimitiveType.TriangleStrip;
                                    indexTable.Indices = triangleStrip;
                                }
                            }
                        }
                    }

                    foreach (var material in meshes.Materials)
                    {
                        material.Shader = "BLINN";

                        //material.Field02 = 0x00000A80;
                        MikuMikuLibrary.Misc.Color asdf = new MikuMikuLibrary.Misc.Color(0, 0, 0, 0);

                        //material.AmbientColor = asdf;
                        //material.EmissionColor = asdf;
                        //material.Shininess = 1;

                        if (material.Ambient.TextureId == 1509989155)
                            material.Ambient.TextureId = -1;
                        if (material.Normal.TextureId == 1509989155)
                            material.Normal.TextureId = -1;
                        if (material.Specular.TextureId == 1509989155)
                        {
                            material.Specular.TextureId = -1;
                            material.SpecularColor = asdf;
                        }
                        //else { material.Field00 = 0x0000002D; }

                        /*
                        
                        // this blacken the screen on STAGE SHADER
                        material.Specular.Field01 = 0x002418C3;
                        material.Specular.Field02 = 0x000000F3;
                        material.Specular.Field05 = 1;
                        material.Specular.Field06 = 1;
                        material.Specular.Field11 = 1;
                        material.Specular.Field16 = 1;
                        material.Specular.Field21 = 1;
                        
                        material.Specular.Field01 = 0x00000000;
                        material.Specular.Field02 = 0x000000F0;
                        material.Specular.Field05 = 0;
                        material.Specular.Field06 = 0;
                        material.Specular.Field11 = 0;
                        material.Specular.Field16 = 0;
                        material.Specular.Field21 = 0;

                        */

                        if (material.Reflection.TextureId == 1509989155)
                            material.Reflection.TextureId = -1;
                        if (material.ToonCurve.TextureId == 1509989155)
                            material.ToonCurve.TextureId = -1;
                        if (material.SpecularPower.TextureId == 1509989155)
                            material.SpecularPower.TextureId = -1;
                        if (material.Texture08.TextureId == 1509989155)
                            material.Texture08.TextureId = -1;
                    }
                }
                counter++;
            }

            textures.Format = BinaryFormat.DT;
            stgpv.Format = BinaryFormat.DT;

            var texturedb = new TextureDatabase();
            texturedb.Load(@"D:\DL\tex_db.bin");

            if (doProcess)
                stgpv.Save("temp\\" + Path.GetFileNameWithoutExtension(filePath) + "_obj.bin", null, texturedb, null);
            objdb.Objects.Add(objentry);

            if (Path.GetFileNameWithoutExtension(filePath).Count() == 8)
            {
                StageEntry stage = new StageEntry();
                stage.Id = FindUnusedID(staged);
                stage.Name = Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8").ToUpper();
                stage.ObjectGroundId = (short)ground_id;
                stage.ObjectGroundIdFlag = (short)objentry.Id;
                stage.ObjectId3 = -1;
                stage.ObjectIdFlag3 = -1;
                stage.ObjectId5 = -1;
                stage.ObjectIdFlag5 = -1;
                stage.ObjectId7 = -1;
                stage.ObjectIdFlag7 = -1;
                stage.RingRectangleX = -8;
                stage.RingRectangleY = -8;
                stage.RingRectangleWidth = 16;
                stage.RingRectangleHeight = 16;
                stage.RingRingHeight = 0;
                stage.RingOutHeight = -1000;
                stage.Field00 = 1;
                stage.Field11 = -1;
                stage.Field02 = -1;

                stage.LensFlareScaleX = -1;
                stage.LensFlareScaleY = -1;
                stage.LensFlareScaleZ = -1;

                stage.ObjectSkyId = -1;
                stage.ObjectSkyIdFlag = -1;
                stage.ObjectReflectId = -1;
                stage.ObjectReflectIdFlag = -1;

                stage.CollisionFilePath = @"rom/STGTST_COLI.000.bin";

                stage.ObjectId1 = (short)objentry.Id;
                stage.StageEffect1 = StageEntry.StageEffect.Empty;
                stage.Auth3dName = "EFF" + stage.Name;
                staged.Stages.Add(stage);
            }

            if (doProcess)
            {
                var newfarc = new FarcArchive();
                newfarc.Add(Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8") + "_obj.bin", "temp\\" + Path.GetFileNameWithoutExtension(filePath) + "_obj.bin");
                newfarc.Add(Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8") + "_tex.bin", "temp\\" + Path.GetFileNameWithoutExtension(filePath) + "_tex.bin");
                newfarc.Alignment = 16;
                newfarc.IsCompressed = false;
                newfarc.Save(acpath + "\\rom\\objset\\" + Path.GetFileNameWithoutExtension(filePath).Replace("stgpv0", "stgpv8") + ".farc");
            }

            texturedb.Save(acpath + @"\rom\objset\tex_db.bin");
        }
    }
}
